package org.activequant.util.log;

import org.activequant.core.domainmodel.account.Order;
import org.activequant.core.domainmodel.data.Quote;
import org.activequant.core.domainmodel.data.TimedValue;
import org.activequant.core.domainmodel.data.ValueSeries;
import org.activequant.core.domainmodel.events.OrderEvent;
import org.activequant.core.domainmodel.events.OrderExecutionEvent;
import org.activequant.core.types.OrderSide;
/**
 * A LoggerBase subclass. Holds the following associated variables:
 * <ul>
 * <li>thePnlValueSeries(ValueSeries)</li>
 * <li>thePnl(double)</li>
 * </ul>
 * @author Dimitar
 *
 */
public class PnlLogger extends LoggerBase {
	/**
	 * if the given event(OrderEvent) is an OrderExecutionEvent, it updates the position/quantity and last price for the id(long) of the given order(Order)
	 * into the inherited thePositions(HashMap&lt;Long, Double&gt;) and theInstrumentValuationPrices(HashMap&lt;Long, Double&gt;)
	 */
	public void log(Order order, OrderEvent event) {
		if(event instanceof OrderExecutionEvent)
		{
			OrderExecutionEvent myEvent = (OrderExecutionEvent)event;
			long iid = order.getInstrumentSpecification().getId();
			// as it is an order execution, we also update the running positions and
			// position values.
			if (!thePositions.containsKey(iid)) {
				thePositions.put(iid, 0.0);
				theInstrumentValuationPrices.put(iid, myEvent.getPrice());
			
				// should also reevaluate the position values ... 
				
			}
			// update the position count.
			double myCurrentPosition = thePositions.get(iid);
			// update the last price as well as the current position
			if (order.getOrderSide().equals(OrderSide.BUY)) {
				thePositions.put(iid, myCurrentPosition + myEvent.getQuantity());
			} else {
				thePositions.put(iid, myCurrentPosition - Math.abs(myEvent.getQuantity()));
			}
		}
	}
	/**
	 * calculates the PnL for the given quote(Quote) and current position and then creates and adds a TimedValue using that PnL and quote.getTimeStamp() 
	 * to the associated thePnlValueSeries(ValueSeries)<br/>
	 * thePnl += (myChangeInPrice * myCurrentPosition * quote.tickValue) / quote.tickSize
	 */
	public void log(Quote quote) {
		long myIId = quote.getInstrumentSpecification().getId();
		if(!thePositions.containsKey(myIId))return;
		// update the position count.
		double myCurrentPosition = thePositions.get(myIId);
		double myLastPrice = theInstrumentValuationPrices.get(myIId);
		double myRelevantQuotePrice = myCurrentPosition > 0 ? quote.getBidPrice() : quote.getAskPrice();
		double myChangeInPrice = myCurrentPosition > 0 ? (quote.getBidPrice() - myLastPrice) : (myLastPrice - quote.getAskPrice());
		//
		double myChangeInPnl = myChangeInPrice * myCurrentPosition;
		thePnl += (myChangeInPnl / quote.getInstrumentSpecification().getTickSize()) * quote.getInstrumentSpecification().getTickValue();
		// track the current valuation price.
		theInstrumentValuationPrices.put(myIId, myRelevantQuotePrice);
		// 
		TimedValue myValue = new TimedValue(quote.getTimeStamp(), thePnl);
		thePnlValueSeries.add(myValue);
	}

	/**
	 * the getter for the pnl value series.<br/>
	 * returns the associated thePnlValueSeries(ValueSeries)
	 * @return 
	 */
	public ValueSeries getPnlValueSeries()
	{
		return thePnlValueSeries;
	}
	/**
	 * private double thePnl = 0.0;
	 */
	private double thePnl = 0.0;
	/**
	 * private ValueSeries thePnlValueSeries = new ValueSeries();
	 */
	private ValueSeries thePnlValueSeries = new ValueSeries();
}
